package xyz.xtt.user.service.impl;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Splitter;
import com.google.common.primitives.Longs;
import com.tongtong.middleware.client.MiddlewareClient;
import com.tongtong.middleware.vo.params.AccountParams;
import com.tongtong.middleware.vo.response.AccountResponse;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.common.response.ApiResult;
import xyz.xtt.common.starter.cache.CacheManager;
import xyz.xtt.common.starter.cache.GlobalTableCache;
import xyz.xtt.user.constants.ErrorMessage;
import xyz.xtt.user.entity.TblUser;
import xyz.xtt.user.enums.SyncUserActionEnum;
import xyz.xtt.user.exception.ChainException;
import xyz.xtt.user.response.ResponseResult;
import xyz.xtt.user.service.ITblUserService;
import xyz.xtt.user.service.ThirdService;
import xyz.xtt.user.utils.AESUtil;
import xyz.xtt.user.utils.AssertUtils;
import xyz.xtt.user.vo.user.JsonRootBean;
import xyz.xtt.user.vo.user.TongTongUserInfo;
import xyz.xtt.user.vo.user.UserInfoResponse;
import xyz.xtt.user.vo.user.UserProfileResource;
import xyz.xtt.user.vo.user.UserResource;

/**
 * 第三方服务请求
 * 
 * @author huqibo
 * @date 2024/11/08
 */
@RefreshScope
@Slf4j
@Service
public class ThirdServiceImpl implements ThirdService {
	public static final String AUTHORIZATION = "Authorization";
	/**
	 * 自动注册的用户id
	 */
	private static final Long AUTO_USER_ID = 100L;
	private static final String SEPARATOR_KEY_VAL = "=";

	private static final String SEPARATOR = "&";

	private static final String MQ = "mq";

	private static final String HTTP = "http";

	@Autowired
	private MiddlewareClient middlewareClient;
	@Value("${user.info.requestUrl}")
	private String userInfoRequestUrl;

	@Value("${user.info.thirdAuthCode}")
	private String thirdAuthCode;
	@Autowired
	private ITblUserService iTblUserService;

	@Value("${user.info.userType:http}")
	private String userType;

	@Value("${user.info.defaultImg:1=avatar/default_male.webp&2=avatar/default_female.webp}")
	private String defaultImg;
	@Autowired
	private CacheManager cacheManager;

	@Value("${user.reg.requestUrl}")
	private String userRegRequestUrl;

	@Override
	public AccountResponse createAndQueryAccount(AccountParams req) {
		ApiResult<AccountResponse> createAndQueryAccount = middlewareClient.createAndQueryAccount(req);
		log.info("createAndQueryAccount response: {}", JSONUtil.toJsonStr(createAndQueryAccount));
		return Optional.ofNullable(createAndQueryAccount).filter(ApiResult::isOk).map(ApiResult::getData).filter(Objects::nonNull).orElse(null);
	}

	@Override
	public TblUser httpUserInfo(String appUserId) {
		HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.NORMAL).connectTimeout(Duration.ofSeconds(30)).version(Version.HTTP_1_1).build();
		String url = String.format(userInfoRequestUrl, appUserId);
		HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).header(AUTHORIZATION, thirdAuthCode).timeout(Duration.ofSeconds(30)).GET().build();
		try {
			String body = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
			JsonRootBean bean = JSONUtil.toBean(body, JsonRootBean.class);
			Optional<UserInfoResponse> data = Optional.ofNullable(bean).filter(x -> x.getCode() == 0).map(JsonRootBean::getData);
			Optional<UserResource> userResource = data.map(UserInfoResponse::getUserResource);
			Optional<UserProfileResource> userProfileResource = data.map(UserInfoResponse::getUserProfileResource);
			TblUser user = userResource.flatMap(x -> userProfileResource.map(y -> httpUser(x, y))).orElse(null);
			log.info("httpUserInfo url:{}", url);
			log.info("httpUserInfo httpUserInfo:{}", JSONUtil.toJsonStr(userResource.isPresent() ? userResource.get() : null));
			log.info("httpUserInfo userProfileResource:{}", JSONUtil.toJsonStr(userProfileResource.isPresent() ? userProfileResource.get() : null));
			log.info("httpUserInfo user:{}", JSONUtil.toJsonStr(user));
			return user;
		} catch (Exception e) {
			log.error("httprequest userinfo uid:{} ex:{}", appUserId, e.getMessage(), e);
			throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
		}
	}

	private String img(String avatarUri, Integer gender) {

		String img = avatarUri;
		if (StringUtils.isNotBlank(img)) {
			// 如果是http开头，去路域名
			if (img.startsWith("http")) {
				try {
					URL url = new URL(img);
					img = url.getPath();
				} catch (Exception e) {
				}
				log.info("avatarUri is http startWith img:{}", img);
			}
		} else {
			// 如果是空的, 就用默认图
			// 如果没有性别设置为男性
			if (Objects.isNull(gender)) {
				gender = 1;
			}
			Map<String, String> map = Splitter.on(SEPARATOR).withKeyValueSeparator(SEPARATOR_KEY_VAL).split(defaultImg);
			img = map.getOrDefault(String.valueOf(gender), StringUtils.EMPTY);
			log.info("avatarUri is empty default　gender:{}, img:{}", gender, img);
		}
		return img;
	}

	private TblUser genUser(Long appUserId, String nickName, String avatarUri, String phone, Integer gender) {
		String up = phone;
		if (StringUtils.isNotBlank(phone)) {
			if (!up.startsWith("86")) {
				up = ("86" + up);
			}
		} else {
			up = StringUtils.EMPTY;
		}

		String img = img(avatarUri, gender);
		log.info("appUserId:{},img:{}", appUserId, img);
		LocalDateTime now = LocalDateTime.now();
		return TblUser
				.builder()
				.id(IdUtil.getSnowflakeNextIdStr())
				.userId(0L)
				.appUserId(appUserId)
				.nickname(nickName)
				.avatarUri(img)
				.phone(up)
				.gender(gender)
				.registerDatetime(now)
				.lastModifyDatetime(now)
				.loginDatetime(now)
				.inviteCode(" ")
				.build();
	}

	private TblUser httpUser(UserResource user, UserProfileResource profile) {
		return genUser(user.getId(), user.getFirstName(), profile.getAvatarUrl(), user.getPhoneNumber(), user.getGender());
	}

	private TblUser getUser(TongTongUserInfo userInfo) {
		if (Objects.equals(userType, HTTP)) {
			return httpUserInfo(userInfo.getUserId());
		} else if (Objects.equals(userType, MQ)) {
			return genUser(Longs.tryParse(userInfo.getUserId()), userInfo.getUserName(), userInfo.getAvatarUrl(), userInfo.getPhone(), userInfo.getGender());
		}
		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void syncUser(TongTongUserInfo userInfo) {
		String phone = userInfo.getPhone();
		SyncUserActionEnum action = SyncUserActionEnum.convert(userInfo.getAction());
		log.info("syncUser user action:{}, userInfo:{}", action, JSONUtil.toJsonStr(userInfo));
		Boolean register = userInfo.getRegister();
		if (Objects.equals(register, Boolean.TRUE)) {
			TblUser user = getUser(userInfo);
			if (Objects.isNull(user)) {
				log.info("syncUser user is null userType:{}", userType);
				return;
			}
			TblUser info = iTblUserService.info(Longs.tryParse(userInfo.getUserId()));
			if (Objects.nonNull(info)) {
				// 本地自动注册的用户,走更新逻辑
				if (Objects.equals(info.getUserId(), AUTO_USER_ID)) {
					boolean updateUser = this.iTblUserService.autoRegUpdateUser(user);
					log.info("syncUser user is exist uid equal appUid update:{}, autoRegUpdateUser:{}", userInfo.getUserId(), updateUser);
				}
				return;
			}
			int length = StringUtils.length(user.getPhone());
			if (length > 13) {
				log.info("syncUser user phone is to tolong uid:{}, len:{}", userInfo.getUserId(), length);
				return;
			}
			saveUser(user);
		} else {
			if (Objects.equals(userInfo.getLogoff(), true)) {
				boolean updateUserStatusLogoff = iTblUserService.updateUserStatusLogoff(Longs.tryParse(userInfo.getUserId()));
				if (updateUserStatusLogoff) {
					// 清除用户维度缓存
					cacheManager.delete(GlobalTableCache.TBL_USER, String.valueOf(userInfo.getUserId()));
					log.info("updateUserStatusLogoff uid:{}", userInfo.getUserId());
				}
				return;
			}
		}
	}

	private void saveUser(TblUser user) {
		user.setPhoneBk(user.getPhone());
		String encrypt = AESUtil.encrypt(user.getPhone());
		user.setPhone(encrypt);
		iTblUserService.save(user);
//		iTblUserChainAccountService.save(buildUserChainAccount(user));
//		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
//			@Override
//			public void afterCommit() {
//				address(String.valueOf(user.getAppUserId()));
//			}
//		});
	}

	@Override
	public Long userReg(String phone, String name) {
		String url = String.format(userRegRequestUrl, phone);
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(URI.create(url))
				.header(AUTHORIZATION, thirdAuthCode)
				.header("Content-Type", "application/json")
				.header("device", "1")
				.header("login-type", "1")
				.header("app-type", "1")
				.header("version", "1.0")
				.header("lang", "zh")
				.header("device-id", "1f2baa3d-bab6-47af-817b-41880db2134c")
				.timeout(Duration.ofSeconds(10))
				.GET()
				.build();
		try {
			HttpClient client = HttpClient.newHttpClient();
			HttpResponse<String> send = client.send(request, HttpResponse.BodyHandlers.ofString());
			int statusCode = send.statusCode();
			String body = send.body();
			log.info("userReg statusCode:{}", statusCode);
			log.info("userReg body:{}", body);
			if (Objects.equals(HttpStatus.HTTP_OK, statusCode)) {
				ResponseResult<Long> data = JSONUtil.toBean(body, new TypeReference<ResponseResult<Long>>() {
				}, false);
				Long uid = data.getData();
				// 防止同步的过程中这边在注册
				TblUser infoWithPhone = this.iTblUserService.info(uid);
				if (Objects.nonNull(infoWithPhone)) {
					return uid;
				}
				AssertUtils.isNull(uid, ErrorMessage.USER_REG_EX);
				AssertUtils.isFalse(uid.longValue() > 1, ErrorMessage.USER_REG_EX);
				// 本地用懚数据预插入
				TblUser user = genUser(uid, name, "", phone, 0);
				user.setUserId(AUTO_USER_ID);
				saveUser(user);
				return uid;
			}
		} catch (IOException | InterruptedException e) {
			log.info("ex:{}", e.getMessage(), e);
		}
		return -1L;
	}
}
